/*
 * Copyright TLR Team, Inc. All Rights Reserved.
 */
package com.tlr.device.rest;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.tfb.rong.Device;
import com.tfb.rong.DeviceDataWithBLOBs;
import com.tfb.rong.HealthAlert;
import com.tfb.rong.Users;
import com.tfb.service.UserAssessmentI;
import static com.tfb.service.utility.HttpUtil.getUserDBID;
import com.tfb.service.utility.JsonUtil;
import com.tfb.service.utility.Utils;
import com.tlr.TlrDeviceException;
import com.tlr.device.model.Alert;
import com.tlr.device.model.AlertResult;
import com.tlr.device.model.DeviceUserBind;
import com.tlr.device.model.Eban;
import com.tlr.device.model.EbanDay;
import com.tlr.device.model.HealthUser;
import com.tlr.device.model.RelationUser;
import com.tlr.device.model.Result;
import com.tlr.device.service.DeviceDatabaseService;
import com.tlr.device.service.EbanDevice10API;
import com.tlr.device.service.EbanDeviceAPI;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;
import javax.ws.rs.DELETE;

@SuppressWarnings("UseSpecificCatch")
@Path("/health_device")
public class HealthDeviceResource {

    private static final Logger log = Logger.getLogger(HealthDeviceResource.class);

    @Context
    ServletContext context;
    DeviceDatabaseService deviceService;
    UserAssessmentI userService;

    private synchronized void initDatabaseService() {
        try {
            if (deviceService == null || userService == null) {
                ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
                initDB(ac);
            }
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"classpath:spring.xml", "classpath:spring-mybatis.xml"});
            initDB(ac);
        }
    }

    private void initDB(ApplicationContext ac) {
        if (deviceService == null) {
            deviceService = (DeviceDatabaseService) ac.getBean("deviceDatabaseService");
        }
        if (userService == null) {
            userService = (UserAssessmentI) ac.getBean("userAssessmentService");
        }
    }

    @Path("/close_case")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> closeAlertCase(HealthAlert alert) {
        try {
            initDatabaseService();
            alert.setStatus(0);
            deviceService.updateByPrimaryKeySelective(alert);
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "保存报警数据错误,请联系管理员");
        }
    }

    @Path("/save_desc")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> saveAlertDesc(HealthAlert alert) {
        try {
            initDatabaseService();
            alert.setStatus(null);
            deviceService.updateByPrimaryKeySelective(alert);
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "保存报警数据错误,请联系管理员");
        }
    }

    @Path("/alert_list")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<HealthAlert>> alertList() {
        try {
            initDatabaseService();
            List<HealthAlert> alertList = deviceService.selectAllAlertByStatus(1);
            for (HealthAlert alert : alertList) {
                HealthUser user = deviceService.getHealthUserMapper().selectByDeviceMac(alert.getCode());
                alert.setHealth_user(user);
            }
            return new Result<>(0, "OK", alertList);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取报警数据错误,请联系管理员");
        }
    }

    @Path("/del_relation")
    @DELETE
    @Consumes(MediaType.APPLICATION_JSON)
    public Result<?> delRelation(@Context HttpServletRequest request,
                                 @QueryParam("code") String code,
                                 @QueryParam("id") long id) {
        EbanDeviceAPI eban = new EbanDeviceAPI(true);
        String token = null;
        try {
            initDatabaseService();
            List<Users> users = deviceService.getUserMapper().selectByDeviceUserBind(code);
            if (users.isEmpty()) {
                return new Result<>(0, "该设备没有绑定用户，请联系管理员。");
            }
            deviceService.getRelationUserMapper().deleteByPrimaryKey(id);
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取报警数据错误,请联系管理员");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/add_relation")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Result<String> addRelation(@Context HttpServletRequest request, String message) {
        EbanDeviceAPI eban = new EbanDeviceAPI(true);
        String token = null;
        try {
            initDatabaseService();
            String userID = getUserDBID(request);
            token = eban.openidLogin(deviceService.getUserMapper().selectByPrimaryKey(userID).getWebchat());
            JsonNode relationNode = JsonUtil.createJson(message);
            String code = relationNode.get("code").asText();
            String name = relationNode.get("name").asText();
            String mobile = relationNode.get("tel").asText();
            List<RelationUser> rUsers = deviceService.getRelationUserMapper().selectAllByTelAndCode(mobile, code);
            if (rUsers.isEmpty()) {
                deviceService.getRelationUserMapper().insertSelective(new RelationUser(name, mobile, code));
                return new Result<>(0, "OK");
            } else {
                return new Result<>(500, "联系人已经存在");
            }
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取报警数据错误,请联系管理员");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/alert_relations")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<RelationUser>> getAlertRelations(@Context HttpServletRequest request,
                                                        @QueryParam("code") String code) {
        EbanDeviceAPI eban = new EbanDeviceAPI(true);
        String token = null;
        try {
            initDatabaseService();
            List<Users> users = deviceService.getUserMapper().selectByDeviceUserBind(code);
            if (users.isEmpty()) {
                return new Result<>(500, "该设备没有绑定用户，请联系管理员。");
            }
            List<RelationUser> rUsers = deviceService.getRelationUserMapper().selectAllByDeviceID(code);
            // TLR want disable the urgent contact person from eban device, just insert contact person in TLR db
            return new Result<>(0, "OK", rUsers);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取报警联系人错误,请联系管理员");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/tlr_urgent_relations")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<JsonNode> getAlertUrgentRelations(@Context HttpServletRequest request,
                                                    @QueryParam("code") String code) {
        EbanDeviceAPI eban = new EbanDeviceAPI(true);
        String token = null;
        try {
            initDatabaseService();
            List<Users> users = deviceService.getUserMapper().selectByDeviceUserBind(code);
            if (users.isEmpty()) {
                return new Result<>(500, "该设备没有绑定用户，请联系管理员。");
            }
            token = eban.openidLogin(users.get(0).getWebchat());
            String relationContent = eban.getRelations(token, code);
            JsonNode node = JsonUtil.createJson(relationContent);
            return new Result<>(0, "OK", node.get("list"));
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取紧急联系专员错误,请联系管理员");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/update_urgent")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<JsonNode> updateUrgentRelations() {
        EbanDeviceAPI eban = new EbanDeviceAPI(true);
        String token = null;
        try {
            initDatabaseService();
            Users record = new Users();
            record.setStatus(1);
            record.setType(4);
            List<Users> users = userService.selectAllUserInfoByStatusAndType(record);
            if (users.isEmpty())
                return new Result<>(500, "无有效紧急联系专员,请联系管理员");
            Users urgentUser = users.get(0);
            token = eban.openidLogin(urgentUser.getWebchat());
            List<Device> devices = deviceService.getAllDevice(1, 1);
            List<Eban> ebans = new ArrayList<>();
            for (Device device : devices) {
                eban.addRelation(token, device.getDevicemac(), urgentUser.getName(), urgentUser.getTel());
                String relationContent = eban.getRelations(token, device.getDevicemac());
                JsonNode node = JsonUtil.createJson(relationContent);
                JsonNode relationsNode = node.get("list");
                Iterator<JsonNode> it = relationsNode.getElements();
                while (it.hasNext()) {
                    JsonNode relation = it.next();
                    if (relation.has("mobile") && urgentUser.getTel().equalsIgnoreCase(relation.get("mobile").asText()))
                        continue;
                    eban.delRelation(token, device.getDevicemac(), relation.get("id").asText());
                }
            }
            eban.logoff(token);
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取紧急联系专员错误,请联系管理员");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/get_bind")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<HealthUser> getBindHeathUser(@Context HttpServletRequest request, @QueryParam("code") String code) {
        try {
            initDatabaseService();
            String userID = getUserDBID(request);
            return new Result<>(0, "OK", deviceService.getHealthUserMapper().selectByUserIDAndDeviceMac(userID, code));
        } catch (Exception ex) {
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "绑定信息读取失败,请联系管理员");
        }
    }

    @Path("/edit_bind")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> editBindDevice(@Context HttpServletRequest request, String message) {
        try {
            HealthUser hu = JsonUtil.readValue(message, HealthUser.class);
            String userID = getUserDBID(request);
            initDatabaseService();
            Device device = new Device();
            device.setDevicemac(hu.getDeviceMac());
            device.setStatus(1);
            deviceService.getDeviceMapper().updateByDeviceMacSelective(device);
            deviceService.getHealthUserMapper().updateByDeviceMacSelective(hu);
            deviceService.getDeviceUserBindMapper().update(new DeviceUserBind(userID, hu.getDeviceMac(), hu.getNickname()));
            return new Result<>(0, "OK");
        } catch (Exception ex) {
            log.error(message);
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "绑定失败,请联系管理员");
        }
    }

    @Path("/add_bind")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> addBindDevice(@Context HttpServletRequest request, String message) {
        try {
            HealthUser hu = JsonUtil.readValue(message, HealthUser.class);
            String userID = getUserDBID(request);
            initDatabaseService();
            if (!deviceService.getDeviceUserBindMapper().selectAllByUserIDAndDeviceID(userID, hu.getDeviceMac()).isEmpty()) {
                return new Result<>(500, "不能重复绑定到一个用户");
            }
            Device device = new Device();
            device.setDevicemac(hu.getDeviceMac());
            device.setDevicename("健康仪");
            device.setStatus(1);
            device.setDevicetype(1);
            if (null == deviceService.getDeviceByMac(hu.getDeviceMac())) {
                deviceService.addDevice(device);
            } else {
                deviceService.getDeviceMapper().updateByDeviceMacSelective(device);
            }
            if (deviceService.getHealthUserMapper().selectByDeviceMac(hu.getDeviceMac()) == null) {
                deviceService.getHealthUserMapper().insertSelective(hu);
            } else {
                deviceService.getHealthUserMapper().updateByDeviceMacSelective(hu);
            }
            deviceService.getDeviceUserBindMapper().insert(new DeviceUserBind(userID, hu.getDeviceMac(), hu.getNickname()));
            return new Result<>(0, "OK");
        } catch (Exception ex) {
            log.error(message);
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "绑定失败,请联系管理员");
        }
    }

    private Result<String> checkAndUpdateUrgentRelationPerson(String userID, String code) {
        /* EbanRecorder eban = new EbanRecorder(true);
         String token = eban.openidLogin(deviceService.getUserMapper().selectByPrimaryKey(userID).getWebchat());
         String relationContent = eban.getRelations(token, code);
         JsonNode node = JsonUtil.createJson(relationContent);
         if (!node.has("list") || !node.get("list").getElements().hasNext()) {
         int ret = eban.addRelation(token, code, name, mobile);
         if (ret != 1)
         return new Result<>(500, "紧急联系人添加错误");
         }*/
        return null;
    }

    @Path("/last_basic_data")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getDeviceLastBasicData(@Context HttpServletRequest request,
                                           @QueryParam("device_id") String deviceID) {
        // Get point and location for the first page
        EbanDeviceAPI ebanAPI = new EbanDevice10API();
        String token = null;
        try {
            initDatabaseService();
            Device device = deviceService.getDeviceInfo(deviceID);
            token = ebanAPI.openidLogin(userService.selectUserByPrimaryKey(getUserDBID(request)).getWebchat());
            JsonUtil jsonU = JsonUtil.createJsonUtility();
            JsonGenerator jsonG = jsonU.getGenerator();
            String date = EbanDeviceAPI.getDayFormat().format(new Date());
            Eban eban = ebanAPI.getLastDeviceData(token, device.getDevicemac(), date);
            jsonG.writeStartObject();
            jsonG.writeStringField("point_data", eban.getPoint());
            jsonG.writeStringField("position_data", eban.getPosition());
            jsonG.writeEndObject();
            return Response.ok().entity(jsonU.toUTF8String()).build();
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return Response.status(500).entity("读取报警数据错误,请联系管理员").build();
        } finally {
            ebanAPI.logoff(token);
        }
    }

    @Path("/last_stat_data")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public EbanDay getDeviceLastData(@Context HttpServletRequest request,
                                     @QueryParam("device_id") String deviceID) throws Exception {
        // Get the last valid health statistics data, example: 2016-01-18 data
        // is not valid, but 2016-01-14 is valid, then the 01-14 is the last
        // statistics data
        EbanDeviceAPI eban = new EbanDeviceAPI();
        String token = null;
        try {
            initDatabaseService();
            Device device = deviceService.getDeviceInfo(deviceID);
            token = eban.openidLogin(userService.selectUserByPrimaryKey(getUserDBID(request)).getWebchat());
            return eban.getDataByDayInfo(token, device.getDevicemac(), EbanDeviceAPI.getDayFormat().format(new Date()));
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/day_detail_stat")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public EbanDay getDayDetailStat(@Context HttpServletRequest request,
                                    @QueryParam("device_id") String deviceID,
                                    @QueryParam("date") String date) throws Exception {
        EbanDeviceAPI eban = new EbanDeviceAPI();
        String token = null;
        try {
            // Eban only can get yesterday statistic data, so add one day to
            // current day to get current day data
            initDatabaseService();
            token = eban.openidLogin(userService.selectUserByPrimaryKey(getUserDBID(request)).getWebchat());
            Device device = deviceService.getDeviceInfo(deviceID);
            EbanDay day = eban.getDataByDayInfo(token, device.getDevicemac(), date);
            String last = eban.getLastSDay(token, device.getDevicemac(), date);
            if (last.isEmpty()) {
                day.setPoint("0");
            } else {
                JsonNode point = JsonUtil.createJson(last);
                day.setPoint(point.has("point") ? point.get("point").asText() : "0");
            }
            return day;
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/day_stat")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getDayStat(@Context HttpServletRequest request,
                               @QueryParam("device_id") String deviceID) throws IOException, ParseException {
        EbanDeviceAPI eban = new EbanDeviceAPI();
        String token = null;
        try {
            initDatabaseService();
            Device device = deviceService.getDeviceInfo(deviceID);
            token = eban.openidLogin(userService.selectUserByPrimaryKey(getUserDBID(request)).getWebchat());
            JsonUtil jsonU = JsonUtil.createJsonUtility();
            JsonGenerator jsonG = jsonU.getGenerator();
            String date = EbanDeviceAPI.getDayFormat().format(new Date());
            String data = eban.getDMessage(token, device.getDevicemac(), date);
            data = JsonUtil.createJson(data).toString();
            jsonG.writeRaw(data);
            return Response.ok().entity(jsonU.toUTF8String()).build();
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return Response.status(500).build();
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/week_stat")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getWeekStat(@Context HttpServletRequest request,
                                @QueryParam("device_id") String deviceID) throws IOException, ParseException {
        EbanDeviceAPI eban = new EbanDeviceAPI();
        String token = null;
        try {
            initDatabaseService();
            Device device = deviceService.getDeviceInfo(deviceID);
            token = eban.openidLogin(userService.selectUserByPrimaryKey(getUserDBID(request)).getWebchat());
            JsonUtil jsonU = JsonUtil.createJsonUtility();
            JsonGenerator jsonG = jsonU.getGenerator();
            String date = EbanDeviceAPI.getDayFormat().format(new Date());
            String data = eban.getSDayRest(token, device.getDevicemac(), date);
            data = JsonUtil.createJson(data).toString();
            jsonG.writeRaw(data);
            return Response.ok().entity(jsonU.toUTF8String()).build();
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/stat_type")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getLast6Month() throws IOException {
        Calendar c = Calendar.getInstance();
        JsonUtil jsonU = JsonUtil.createJsonUtility();
        JsonGenerator jsonG = jsonU.getGenerator();
        jsonG.writeStartObject();
        jsonG.writeArrayFieldStart("stat_type");
        jsonG.writeStartObject();
        jsonG.writeStringField("value", "1");
        jsonG.writeStringField("name", "当日统计");
        jsonG.writeEndObject();
        jsonG.writeStartObject();
        jsonG.writeStringField("value", "2");
        jsonG.writeStringField("name", "当周统计");
        jsonG.writeEndObject();
        for (int i = 0; i < 15; ++i) {
            c.add(Calendar.DAY_OF_MONTH, -1);
            String date = EbanDeviceAPI.getDayFormat().format(c.getTime());
            jsonG.writeStartObject();
            jsonG.writeStringField("value", date);
            jsonG.writeStringField("name", date);
            jsonG.writeEndObject();
        }
        jsonG.writeEndArray();
        jsonG.writeEndObject();
        return Response.ok().entity(jsonU.toUTF8String()).build();
    }

    private Eban getLastEbanInfoFromDatabase(Device device) {
        try {
            DeviceDataWithBLOBs ddb = new DeviceDataWithBLOBs();
            ddb.setDeviceid(device.getDevicemac());
            List<DeviceDataWithBLOBs> ddbs = deviceService.getDeviceDataMapper().selectLastDeviceData(ddb);
            log.info("Eban data count: " + ddbs.size());
            if (ddbs.isEmpty()) {
                return null;
            }
            return JsonUtil.readValue(ddbs.get(0).getData(), Eban.class);
        } catch (IOException ex) {
            log.error(Utils.getFullException(ex));
            return null;
        }
    }

    private Eban getEbanInfoFromEbanServer(Device device) {
        String token = null;
        EbanDevice10API ebanRecorder = new EbanDevice10API();
        try {
            List<Users> users = deviceService.getUserMapper().selectByDeviceUserBind(device.getDevicemac());
            if (users.isEmpty()) {
                log.error(String.format("The device %s is not binded to a user", device.getDevicemac()));
                return null;
            }
            Users user = users.get(0);
            HealthUser healthUser = deviceService.getHealthUserMapper().selectByDeviceMac(device.getDevicemac());
            if (healthUser == null) {
                log.error(String.format("The device %s doesn't have health user", device.getDevicemac()));
            } else {
                SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
                token = ebanRecorder.openidLogin(user.getWebchat());
                Eban eban = ebanRecorder.getLastDeviceData(token, device.getDevicemac(), sf.format(new Date()));
                eban.setStorage_id(device.getDeviceid());
                eban.setAccount(device.getRealname());
                eban.setNick_name(healthUser.getName());
                eban.setOwner(healthUser.getName() != null ? healthUser.getName() : "未知名字");
                eban.setMobile(healthUser.getTel());
                return eban;
            }
            ebanRecorder.logoff(token);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            ebanRecorder.logoff(token);
        }
        return null;
    }

    @Path("/fast_map_info")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<Eban>> fastListMapInfo() {
        try {
            initDatabaseService();
            List<Device> devices = deviceService.getAllDevice(1, 1);
            List<Eban> ebans = new ArrayList<>();
            for (Device device : devices) {
                log.info("Search eban :" + device.getDevicemac());
                Eban eban = this.getLastEbanInfoFromDatabase(device);
                if (eban != null) {
                    if (eban.getPoint() == null)
                        eban.setPoint("0");
                    ebans.add(eban);
                }
            }
            return new Result<>(0, "成功", ebans);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "读取地图数据错误，请联系管理员");
        }
    }

    @Path("/map_info")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<Eban>> listMapInfo() {
        // Used in air map of dashboard
        initDatabaseService();
        List<Device> devices = deviceService.getAllDevice(1, 1);
        List<Eban> ebans = new ArrayList<>();
        for (Device device : devices) {
            Eban eban = getEbanInfoFromEbanServer(device);
            if (eban != null) {
                ebans.add(eban);
            }
        }
        return new Result<>(0, "成功", ebans);
    }

    @Path("ebanservice")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> getEbanSocketAddress(@Context HttpServletRequest request) {
        return new Result<>(0, "OK", AppContext.getEbanWebsocketAddress());
    }

    @Path("/alert")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public AlertResult pushAlert(Alert alert) {
        try {
            int errorStepCount = 0;
            log.info("Recieved alert: " + JsonUtil.writeValue(alert));
            try {
                initDatabaseService();
                // Check if already get the alert, because there is a bug in eban they send the same alert twice.
                if (0 < deviceService.getAlertMapper().checkExist(alert.getCode(), alert.getTime() + "000", alert.getType())) {
                    log.info("Alert already handled! ignore it");
                    AlertResult ar = new AlertResult();
                    ar.setErrorCode(0);
                    ar.setMsg("OK");
                    return ar;
                }
                // insert alert to database
                // The time is seconds 
                HealthUser user = deviceService.getHealthUserMapper().selectByDeviceMac(alert.getCode());
                alert.setHealth_user(user);
                alert.setTime(Long.toString(Long.parseLong(alert.getTime()) * 1000));
                HealthAlert ha = new HealthAlert(alert);
                ha.setId(String.format("WA%06d", userService.getNextID("alert")));
                ha.setLastmodify(new Date());
                deviceService.insertHealthDeviceAlert(ha);
                Device device = deviceService.getDeviceByMac(alert.getCode());
                alert.setDevice(device);
                device.setDevicepwd("");
            } catch (Exception e) {
                ++errorStepCount;
                log.error(Utils.getFullException(e));
            }
            try {
                // --------notify peer tomcat
                if (AppContext.getEbanSocketService() != null) {
                    AppContext.getEbanSocketService().notifyMessage(alert);
                }
            } catch (Exception e) {
                ++errorStepCount;
                log.error(Utils.getFullException(e));
            }
            NotifyPeer(alert);
            if (errorStepCount > 0) {
                throw new Exception("The important notify steps failed");
            }
            AlertResult ar = new AlertResult();
            ar.setErrorCode(0);
            ar.setMsg("OK");
            return ar;
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            AlertResult ar = new AlertResult();
            ar.setErrorCode(-1);
            ar.setMsg("Failed to handle alert for device '" + alert.getCode() + "'");
            return ar;
        }
    }

    public String getPeerAddress() throws IOException {
        String propFile = AppContext.getPeerNotifyAddress();
        try (InputStream in = new FileInputStream(new File(propFile))) {
            Properties props = new Properties();
            props.load(in);
            return props.getProperty("alert_peer_address");
        }
    }

    private Result<String> NotifyPeer(Alert data) {
        try {
            // Set -2 as a flag for notifiy peer.
            Client client = Client.create();
            String localAddress = getPeerAddress();
            log.info("Local address: " + localAddress);
            WebResource webResource = client.resource(localAddress);
            ClientResponse clientResp = webResource.type(MediaType.APPLICATION_JSON).post(ClientResponse.class, JsonUtil.writeValue(data));
            String respStr = clientResp.getEntity(String.class);
            log.info(respStr);
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, e.fillInStackTrace().getMessage());
        }
    }

    @Path("/notify")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> NotifyAlert(Alert alert) {
        log.info("Recived peer alert: " + JsonUtil.writeValue(alert));
        try {
            if (AppContext.getEbanSocketService() != null) {
                alert.getCode();
                AppContext.getEbanSocketService().notifyMessage(alert);
            }
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(-1, "发送通知消息失败");
        }
    }

    @Path("/binded")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<Eban>> listBindDevcies(@Context HttpServletRequest request) {
        EbanDeviceAPI eban = new EbanDeviceAPI();
        String token = null;
        try {
            // Used in mobile
            initDatabaseService();
            String userDBID = getUserDBID(request);
            Users user = userService.selectUserByPrimaryKey(userDBID);
            token = eban.openidLogin(user.getWebchat());
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            List<Device> devices = deviceService.getDeviceMapper().selectDeviceWithBindedInfoByUserIDAndDeviceType(userDBID, 1);
            List<Eban> ebans = new ArrayList<>();
            for (Device device : devices) {
                Eban ebanData = eban.getLastDeviceData(token, device.getDevicemac(), sf.format(new Date()));
                ebanData.setStorage_id(device.getDeviceid());
                ebanData.setAccount(device.getRealname());
                ebanData.setNick_name(device.getBindNickName());
                ebanData.setOwner(device.getBinduser());
                ebanData.setMobile(user.getTel());
                ebans.add(ebanData);
            }
            return new Result<>(0, "成功", ebans);
        } catch (Exception e) {
            log.error(e.fillInStackTrace());
            return new Result<>(500, "获取用户健康精灵列表失败");
        } finally {
            eban.logoff(token);
        }
    }

    @Path("/get_exist_health_user")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<HealthUser> getExistHeathUser(@Context HttpServletRequest request, @QueryParam("code") String code) {
        try {
            initDatabaseService();
            return new Result<>(0, "OK", deviceService.getHealthUserMapper().selectByDeviceMac(code));
        } catch (Exception ex) {
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "绑定信息读取失败,请联系管理员");
        }
    }

    @Path("/all_health_user")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<HealthUser>> allHealthUsers() {
        try {
            initDatabaseService();
            List<HealthUser> users = deviceService.getHealthUserMapper().selectAllHealthUser();
            DeviceDataWithBLOBs ddb = new DeviceDataWithBLOBs();
            for (HealthUser user : users) {
                ddb.setDeviceid(user.getDeviceMac());
                List<DeviceDataWithBLOBs> ddbs = deviceService.getDeviceDataMapper().selectLastDeviceData(ddb);
                if (!ddbs.isEmpty()) {
                    user.setPoint(ddbs.get(0).getPoint());
                } else {
                    user.setPoint(0);
                }
            }
            return new Result<>(0, "OK", users);
        } catch (Exception ex) {
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "查询健康用户统计信息错误,请联系管理员");
        }
    }

    @Path("/edit_health_user")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> editHealthUser(String message) {
        try {
            HealthUser hu = JsonUtil.readValue(message, HealthUser.class);
            initDatabaseService();
            deviceService.getHealthUserMapper().updateByDeviceMacSelective(hu);
            return new Result<>(0, "OK");
        } catch (Exception ex) {
            log.error(message);
            log.error(Utils.getFullException(ex));
            return new Result<>(500, "更新健康用户错误,请联系管理员");
        }
    }
}
